using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using StackExchange.Redis;

namespace ORS.OrderRobot.Cache
{
    /// <summary>
    /// redis缓存实现
    /// </summary>
    public class RedisCache : ICache
    {
        private readonly IConnectionMultiplexer _redis;
        private readonly IDatabase _db;
        private readonly RedisOptions _options;
        private static readonly TimeSpan DefaultExpiration = TimeSpan.FromDays(7); // 默认7天过期

        public RedisCache(IConnectionMultiplexer redis, RedisOptions options)
        {
            _redis = redis ?? throw new ArgumentNullException(nameof(redis));
            _options = options ?? throw new ArgumentNullException(nameof(options));
            _db = redis.GetDatabase(_options.DefaultDatabase);
        }

        public async Task SetAsync(string key, object value, TimeSpan? expiration = null)
        {
            var jsonValue = JsonSerializer.Serialize(value);
            await _db.StringSetAsync(key, jsonValue, expiration ?? DefaultExpiration);
        }

        public async Task<T> GetAsync<T>(string key)
        {
            var value = await _db.StringGetAsync(key);
            if (!value.HasValue)
            {
                return default;
            }

            return JsonSerializer.Deserialize<T>(value);
        }

        public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T?>> factory, TimeSpan? expiration = null)
        {
            var value = await GetAsync<T>(key);
            if (value != null)
            {
                return value;
            }

            value = await factory();
            if(value!=null) await SetAsync(key, value, expiration);
            return value;
        }

        public Task RemoveAsync(string key)
        {
            return _db.KeyDeleteAsync(key);
        }

        public async Task<IEnumerable<string>> GetAllKeysAsync(string? prefix = null)
        {
            var allKeys = new List<string>();
            var endpoints = _redis.GetEndPoints();
            foreach (var endpoint in endpoints)
            {
                var server = _redis.GetServer(endpoint);
                await foreach (var key in server.KeysAsync(database: _db.Database))
                {
                    var keyStr = key.ToString();
                    if (prefix == null || keyStr.StartsWith(prefix))
                    {
                        allKeys.Add(keyStr);
                    }
                }
            }
            return allKeys;
        }
    }
} 